/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Vehiculo;

import BESA.ExceptionBESA;
import BESA.Kernell.Agent.Event.DataBESA;
import BESA.Kernell.Agent.Event.EventBESA;
import BESA.Kernell.Agent.GuardBESA;
import BESA.Kernell.Agent.StateBESA;
import BESA.Kernell.System.Directory.AgHandlerBESA;
import BESA.Log.ReportBESA;
import Data.ActionData;
import Data.SensorData;
import World.Behavior.UpdateGuard;
import java.util.ArrayList;
import java.util.List;
import mundo.Malla;
import mundo.OpcionVehiculo;
import mundo.Punto;
import mundo.Tramo;
import mundo.Cruce;
import static mundo.Tramo.UNIDIRECCIONAL;

/**
 *
 * @author Andres
 */
public class SensorGuard extends GuardBESA {

    public static final int DERECHA = 0;
    public static final int IZQUIERDA = 1;
    public static final int ARRIBA = 2;
    public static final int ABAJO = 3;

    @Override
    public boolean funcEvalBool(StateBESA objEvalBool) {
        return true;
    }

    @Override
    public void funcExecGuard(EventBESA ebesa) {
        SensorData data = (SensorData) ebesa.getData();
        EstadoVehiculo ev = (EstadoVehiculo) this.getAgent().getState();
        //OpcionVehiculo opv = getOpciones(ev.getUbicacion(), data.getMalla());
        if(data.getAction()!=null){
            if(data.getAction().equals("invisible")){
                System.out.println(ev.Nombre+" Soy Invicible............................!!!!!!!!!!!!!!!!!!!!!!="+data.getData());
                if(data.getData()=="true"){
                    ev.invisible=true;
                }else{
                    ev.invisible=false;
                }
            }
        }
        DataBESA dataAction;
        boolean mover = false;
        if(ev.getDestinoInVia()==null){
            ev.SetDestinoInVia(data.getMalla());
        }
        if(!ev.heLLegado()){
            Punto nuevoPunto = getNextPunto(ev, data.getMalla());
            nuevoPunto=this.hayVehiculo(nuevoPunto,data.getMalla());
            //System.out.println("["+ev+"]");
            /*
            if (opv.isAvanzar()) {
                nuevoPunto = adelante(ev.getUbicacion(), opv.getTrActual());
                mover = true;
            } else if (opv.isCarrilDerecha()) {
                nuevoPunto = derecha(ev.getUbicacion(), opv.getTrActual());
                mover = true;
            }
            */

            //System.out.println("mover=>"+mover);
            if (nuevoPunto!=null) {
                dataAction = new ActionData(this.getAgent().getAlias(), "move", nuevoPunto.getX(), nuevoPunto.getY());
                ev.setUbicacion(nuevoPunto);
                Malla m=data.getMalla();
                m.UpdateVehiculo(ev);
                data.setMalla(m);
                EventBESA event = new EventBESA(UpdateGuard.class.getName(), dataAction);
                AgHandlerBESA ah;
                try {
                    ah = getAgent().getAdmLocal().getHandlerByAlias("WORLD");
                    ah.sendEvent(event);
                } catch (ExceptionBESA e) {
                    ReportBESA.error(e);
                }
            }
        }
    }

    public Punto getNextPunto(EstadoVehiculo ev, Malla malla) {
        Punto NuevoPunto = null;
        //System.out.println(ev.getUbicacion()+"Distancia destino->"+ev.getUbicacion().Distancia(ev.getDestinoInVia()));
        if(ev.getUbicacion().Distancia(ev.getDestinoInVia())!=0){
            if(!ev.getUbicacion().equals(ev.getDestino())){
            Tramo tr= getTramo(ev.getUbicacion(),malla);
                if(tr!=null){
                    NuevoPunto=tr.getNext(ev.getUbicacion());
                }else{
                    tr=this.BuscarNextTramo(ev.getUbicacion(),ev.getDestino(),malla);
                    //System.out.println("tramo BuscarNextTramo->"+tr);
                    if(tr!=null){
                        NuevoPunto=tr.irHaciaTramo(ev.getUbicacion());
                    }
                }
            }else{
                NuevoPunto=this.irViaDirecta(ev);
                ev.setDestino(NuevoPunto);
            }
        }
        
        return NuevoPunto;
        
    }

    public Tramo BuscarNextTramo(Punto ubicacion,Punto destino, Malla malla){
        List<Tramo> tramos=getTramos(ubicacion,malla);
        Tramo tr=null;
        Tramo tr2=null;
        double disMaxC=Double.MAX_VALUE;
        double disMaxT=Double.MAX_VALUE;
            for(Tramo t : tramos){
                //esta en el tramo?
                if(t.inTramo(destino)){
                    return t;
                }
                
                Cruce c=t.nearCruce(destino);
                double temp=c.Distancia(destino);
                if(disMaxC>temp){
                    disMaxC=temp;
                    tr=t;
                }
                
                temp=t.Distancia(destino);
                if(disMaxT>temp){
                    disMaxT=temp;
                    tr2=t;
                }
            }
            if(disMaxC<disMaxT){
                return tr;
            }
            return tr2;
    }
    
    
    public Tramo getTramo(Punto ubicacion,Malla malla){
        for(Tramo tr : malla.getListaTramos()){
            if(tr.inTramo(ubicacion)){
                return tr;
            }
        }
        return null;
    }
    
    public List<Tramo> getTramos(Punto ubicacion,Malla malla){
        List<Tramo> tramos=new ArrayList();
        for(Tramo tr : malla.getListaTramos()){
            Cruce cr=tr.getCruce(ubicacion);
            if(cr!=null){
                tramos.add(tr);
            }
        }
        return tramos;
    }
    /*
    public Cruce getCruce(Punto ubicacion,Malla malla){
        for(Cruce cr : malla.getListaCruces()){
                return cr.nearCruce(ubicacion);
        }
        return null;
    }*/
    /*
    public OpcionVehiculo getOpciones(Punto ubicacion, Malla malla) {
        OpcionVehiculo op = new OpcionVehiculo();
        Tramo tr = null;
        int i;
        for (i = 0; i < malla.getListaTramos().size(); i++) {
            tr = malla.getListaTramos().get(i);
            System.out.println("tr.getInfIz().getX() <= ubicacion.getX()"+tr.+ "<=" +ubicacion.getX());
            if (tr.getInfIz().getX() <= ubicacion.getX() && tr.getInfIz().getY() <= ubicacion.getY()
                    && tr.getSupDer().getX() >= ubicacion.getX() && tr.getSupDer().getY() >= ubicacion.getY()) {
                //break;
            }
        }
        //System.out.println("malla.getListaTramos().size()->"+malla.getListaTramos().size()+">"+i);
        if (i < malla.getListaTramos().size()) {
            
            op.setTrActual(tr);
            op.setAvanzar(verAdelante(ubicacion, tr, malla.getListaPuntos()));
            op.setCarrilDerecha(verDerecha(ubicacion, tr, malla.getListaPuntos()));
            op.setCarrilIzquierda(verIzquierda(ubicacion, tr, malla.getListaPuntos()));
                   
        }
        return op;
    }
*/
    public boolean verAdelante(Punto p, Tramo tr, ArrayList<Punto> listaPuntos) {
        boolean ans = false;
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getSupDer().getX() > p.getX()) {
                    ans = !buscaPunto(p, listaPuntos, DERECHA);
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getInfIz().getX() < p.getX()) {
                    ans = !buscaPunto(p, listaPuntos, IZQUIERDA);
                }
            }
        } else {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getSupDer().getY() > p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, ABAJO);
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getInfIz().getY() < p.getY()) {
                    ans = buscaPunto(p, listaPuntos, ARRIBA);
                }
            }
        }
        return ans;
    }

    public boolean verDerecha(Punto p, Tramo tr, ArrayList<Punto> listaPuntos) {
        boolean ans = false;
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getSupDer().getY() > p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, ABAJO);
                    
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getSupDer().getY() < p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, ARRIBA);
                }
            }
        } else {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getInfIz().getX() < p.getX()) {
                    ans = !buscaPunto(p, listaPuntos, IZQUIERDA);
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getSupDer().getX() > p.getX()) {
                    ans = !buscaPunto(p, listaPuntos, DERECHA);
                }
            }
        }
        
        return ans;
    }

    public boolean verIzquierda(Punto p, Tramo tr, ArrayList<Punto> listaPuntos) {
        boolean ans = false;
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getInfIz().getY() < p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, ARRIBA);
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getSupDer().getY() > p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, ABAJO);
                }
            }
        } else {
            if (tr.getDireccion() == Tramo.UNIDIRECCIONAL) {
                if (tr.getSupDer().getX() > p.getX()) {
                    ans = !buscaPunto(p, listaPuntos, DERECHA);
                }
            } else if (tr.getDireccion() == Tramo.UNIDIRECCIONAL_INVERTIDA) {
                if (tr.getInfIz().getY() < p.getY()) {
                    ans = !buscaPunto(p, listaPuntos, IZQUIERDA);
                }
            }
        }
        return ans;
    }

    public boolean buscaPunto(Punto punto, ArrayList<Punto> listaPuntos, int direccion) {
        boolean ans = false;
        for (int i = 0; i < listaPuntos.size(); i++) {
            if (direccion == DERECHA) {
                if (listaPuntos.get(i).getX() == (punto.getX() + 1) && listaPuntos.get(i).getY() == punto.getY()) {
                    ans = true;
                    break;
                }
            } else if (direccion == ARRIBA) {
                if (listaPuntos.get(i).getY() == (punto.getY() - 1)&& listaPuntos.get(i).getX() == punto.getX()) {
                    ans = true;
                    break;
                }
            } else if (direccion == IZQUIERDA) {
                if (listaPuntos.get(i).getX() == (punto.getX() - 1)&& listaPuntos.get(i).getY() == punto.getY()) {
                    ans = true;
                    break;
                }
            } else if (direccion == ABAJO) {
                if (listaPuntos.get(i).getY() == (punto.getY() + 1)&& listaPuntos.get(i).getX() == punto.getX()) {
                    ans = true;
                    break;
                }
            }
        }
        //System.out.println("direccion=>"+direccion);
        return ans;
    }

    public Punto adelante(Punto p, Tramo tr) {
        Punto ans = new Punto(p.getX(), p.getY());
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setX(p.getX() + 1);
            }
        } else {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setY(p.getY() + 1);
            }
        }
        return ans;
    }

    public Punto derecha(Punto p, Tramo tr) {
        Punto ans = new Punto(p.getX(), p.getY());
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setY(p.getY() + 1);
            }
        } else {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setX(p.getX() - 1);
            }
        }
        return ans;
    }

    public Punto izquierda(Punto p, Tramo tr) {
        Punto ans = new Punto(p.getX(), p.getY());
        if (tr.isHorizontal()) {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setY(p.getY() - 1);
            }
        } else {
            if (tr.getDireccion() == UNIDIRECCIONAL) {
                ans.setX(p.getX() + 1);
            }
        }
        return ans;
    }

    private Punto irViaDirecta(EstadoVehiculo ev) {
        Punto nuevoPunto=null;
        if(ev.getDestinoInVia().getX()>ev.getUbicacion().getX()){
            nuevoPunto=new Punto(ev.getUbicacion().getX()+1,ev.getUbicacion().getY());
        }else if(ev.getDestinoInVia().getX()<ev.getUbicacion().getX()){
            nuevoPunto=new Punto(ev.getUbicacion().getX()-1,ev.getUbicacion().getY());
        }else if(ev.getDestinoInVia().getY()>ev.getUbicacion().getY()){
            nuevoPunto=new Punto(ev.getUbicacion().getX(),ev.getUbicacion().getY()+1);
        }else if(ev.getDestinoInVia().getY()<ev.getUbicacion().getY()){
            nuevoPunto=new Punto(ev.getUbicacion().getX(),ev.getUbicacion().getY()-1);
        }
        return nuevoPunto;
    }

    private Punto hayVehiculo(Punto nuevoPunto, Malla malla) {
        Punto p=nuevoPunto;
        
        for(int i=0;i<malla.getListaVehiculos().size();i++){
            EstadoVehiculo es=malla.getListaVehiculos().get(i);
            if(es.invisible){
                if(es.getUbicacion().equals(nuevoPunto)){
                    DataBESA dataAction;
                    dataAction = new SensorData();
                    ((SensorData)dataAction).ActionData("invisible","true");
                    EventBESA event = new EventBESA(SensorGuard.class.getName(), dataAction);
                    AgHandlerBESA ah;
                    try {
                        ah = getAgent().getAdmLocal().getHandlerByAlias(es.Nombre);
                        ah.sendEvent(event);
                    } catch (ExceptionBESA e) {
                        ReportBESA.error(e);
                    }
                    return null;
                }
            }
        }
        
        return p;
    }
}
